package m.common.model.util;

import api.util.ApiConvertDataSupport;
import m.common.model.*;
import m.common.model.config.ModelConfig;
import m.system.db.DBManager;
import m.system.exception.MException;
import m.system.util.ArrayUtil;

import java.sql.SQLException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ModelUpdate<T extends Model> {
    private final Class<T> clazz;
    private final List<String> updateFieldList;
    private final Map<String,String> fieldValueMap;
    private final Map<String,Object> objectValueMap;
    private final TableMeta tableMeta;
    private final Map<String, FieldMeta> fieldMap;
    private final Map<String, LinkTableMeta> linkTableMap;
    private ModelUpdate(Class<T> clazz) throws MException {
        this.clazz=clazz;
        this.updateFieldList=new ArrayList<>();
        this.fieldValueMap=new HashMap<>();
        this.objectValueMap=new HashMap<>();
        // 获得对象的类型
        tableMeta= ModelConfig.getTableMeta(clazz);
        if(null==tableMeta) throw new MException(ModelQueryUtil.class,clazz.getName()+"没有对应的表!");
        fieldMap=ModelConfig.getFieldMetaMap(clazz);
        linkTableMap=ModelConfig.getLinkTableMetaMap(clazz);
    }

    /**
     * 初始化更新类
     */
    public static <T extends Model> ModelUpdate<T> init(Class<T> clazz) throws MException {
        return new ModelUpdate<>(clazz);
    }

    /**
     * 通过表达式更新字段 例如：concat(#{字段},'-'#{字段})
     */
    public ModelUpdate<T> setExp(String field,String fieldExp){
        updateFieldList.add(field);
        fieldValueMap.put(field,fieldExp);
        return this;
    }
    /**
     * 添加通过自身属性更新字段
     */
    public ModelUpdate<T> set(String[] field){
        updateFieldList.add(field[0]);
        fieldValueMap.put(field[0],"#{"+field[1]+"}");
        return this;
    }

    /**
     * 添加通过属性更新字段
     */
    public ModelUpdate<T> set(String field,Object value){
        updateFieldList.add(field);
        objectValueMap.put(field,value);
        return this;
    }

    /**
     * 通过添加其他模型汇总值更新字段
     * queryFieldExp 包含#{queryClass的字段} 例如：sum(#{amount})
     */
    public <E extends Model> ModelUpdate<T> set(String field,Class<E> queryClass,String queryFieldExp,QueryCondition cond){
        updateFieldList.add(field);
        Map<String,String> fm=new HashMap<>();
        fm.put("oid",queryFieldExp);
        objectValueMap.put(field,ModelQueryList.instance(queryClass,new String[]{"oid"},new QueryPage(0,1),cond,fm));
        return this;
    }

    /**
     * 通过主键执行更新
     */
    public int execute(String oid) throws MException {
        return execute(null,oid);
    }

    /**
     * 根据条件更新
     */
    public int execute(QueryCondition condition) throws MException {
        return execute(condition,null);
    }
    private int execute(QueryCondition condition,String oid) throws MException {
        StringBuilder fieldString=new StringBuilder();
        List<Object> valueParams= new ArrayList<>();
        if(clazz.isAssignableFrom(SysTimeModel.class)){
            fieldString.append(",").append(getDbField("sysUpdateTime")).append("=?");
            valueParams.add(new Date());
        }
        for(String key : updateFieldList){
            if(fieldValueMap.containsKey(key)){
                fieldString.append(",").append(getDbField(key)).append("=").append(convertDbField(fieldValueMap.get(key)));
            }else if(objectValueMap.containsKey(key)){
                Object value=objectValueMap.get(key);
                if(null==value){
                    fieldString.append(",").append(getDbField(key)).append("=null");
                }else if(value instanceof ModelQueryList){
                    QueryParameter queryParam=((ModelQueryList)value).getQueryParameter();
                    fieldString.append(",").append(getDbField(key)).append("=(").append(queryParam.getSql()).append(")");
                    valueParams.addAll(queryParam.getValueList());
                }else if(value.getClass().isArray()){
                    fieldString.append(",").append(getDbField(key)).append("=?");
                    valueParams.add(ArrayUtil.connection((Object[]) value,","));
                }else if(value instanceof Model) {
                    fieldString.append(",").append(getDbField(key)).append("=?");
                    valueParams.add(((Model)value).getOid());
                }else{
                    fieldString.append(",").append(getDbField(key)).append("=?");
                    valueParams.add(value);
                }
            }
        }
        if(fieldString.length()<=0){
            throw new MException(ModelUpdateUtil.class,"没有更新的属性!");
        }
        StringBuilder sql=new StringBuilder("UPDATE ").append(tableMeta.name());
        sql.append(" SET ").append(fieldString.substring(1));
        ModelQueryList queryList=null;
        if(null!=condition) {
            queryList = ModelQueryList.instance(clazz, new String[]{"oid"}, null, condition);
            QueryParameter queryParam = queryList.getQueryParameter();
            sql.append(" WHERE ").append(tableMeta.oidField()).append(" in(select t0_oid from (");
            sql.append(queryParam.getSql());
            sql.append(") a)");
            valueParams.addAll(queryParam.getValueList());
        }else if(null!=oid){
            sql.append(" WHERE ").append(tableMeta.oidField()).append("=?");
            valueParams.add(oid);
        }else{
            throw new MException(this.getClass(),"没有更新条件");
        }
        try {
            int num= DBManager.executeUpdate(sql.toString(),valueParams.toArray(new Object[]{}));
            if(null!=queryList) {
                //数据转换支撑记录
                ApiConvertDataSupport.addModelUpdate(clazz, queryList);
            }else{
                //数据转换支撑记录
                ApiConvertDataSupport.addModelUpdate(clazz, oid);
            }
            return num;
        } catch (SQLException e) {
            throw new MException(ModelUpdateUtil.class,"更新属性失败!"+e.getMessage());
        }
    }
    private String convertDbField(String exp) throws MException {
        Pattern pattern=Pattern.compile("\\#\\{.+?\\}");
        Matcher matcher=pattern.matcher(exp);
        while(matcher.find()){
            String str=matcher.group();
            String ns=str.substring(2,str.length()-1);
            exp = exp.replace(str, getDbField(ns));
        }
        return exp;
    }
    private String getDbField(String field) throws MException {
        if(field.endsWith(".oid")) field=field.substring(0,field.length()-4);
        if(fieldMap.containsKey(field)) return fieldMap.get(field).name();
        if(linkTableMap.containsKey(field)) return linkTableMap.get(field).name();
        throw new MException(this.getClass(),"没有找到"+field+"字段");
    }

//    public static void main(String[] a) throws MException {
//        ModelUpdate.init(ServerRequest.class)
//                .set("accessLong", ServerRequestDetail.class,"sum(#{accessLong})*10", QueryCondition.eq("serverRequest.oid","IA9LRS8KX01W"))
//                .set(new String[]{"avgLong","accessLong"})
//                .set("suffix",new Object[]{"1","2"})
//                .setExp("suffix","concat('.',#{avgLong})")
//                .execute(QueryCondition.eq("oid","IA9LRS8KX01W"));
//    }
}
